%%% File    : web.erl
%%% Author  :  <>
%%% Description : 
%%% Created : 23 Mar 2011 by  <>

-module(web).

-behaviour(gen_server).

-export([start/0, start_link/0]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	terminate/2, code_change/3]).

-export([acceptor/3]).

-import(regexp,[split/2]).  

-define(defPort, 8080).
-define(docRoot, "public").

-define(SERVER, ?MODULE).

-record(state, {lsock,
	       port,
	       root,
	       pool}).

%%%-----------
start() ->
    gen_server:start({local, ?SERVER}, ?MODULE, [], []).

start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%----
init([]) ->
    process_flag(trap_exit, true),
    case gen_tcp:listen(?defPort, [binary, {packet,0}, {active, false}]) of
	{ok, Lsock} ->
	    Fun = fun(_, List) ->
			  Pid = spawn_link(?MODULE, acceptor, [self(), Lsock, ?docRoot]),
			  [Pid|List] end,
	    Pool = lists:foldl(Fun, [], lists:seq(1, 10)),
	    {ok, #state{lsock=Lsock,
		       port=?defPort,
		       pool=Pool,
		       root=?docRoot}};
	{error, Reason} ->
	    {stop, Reason}
    end.

handle_call(_Req, _From, S) ->
    {reply, ok, S}.

handle_cast({acceptor, Pid}, S=#state{lsock=Lsock,
			      pool=Pool}) ->
    Npid = spawn_link(?MODULE, acceptor, [self(), Lsock, ?docRoot]),
    {noreply, S#state{pool=[Npid|lists:delete(Pid, Pool)]}};

handle_cast(_Msg, S) ->
    {noreply, S}.

handle_info({'EXIT', Pid, _Reason}, S=#state{lsock=Lsock,
					    pool=Pool}) ->
    case lists:member(Pid, Pool) of
	true ->
	     Npid = spawn_link(?MODULE, acceptor, [self(), Lsock, ?docRoot]),
	    {noreply, S#state{pool=[Npid|lists:delete(Pid, Pool)]}};
	false ->
	    {noreply, S}
    end;

handle_info(_Info, S) ->
    {noreply, S}.

terminate(_Reason, _S) ->
    ok.

code_change(_Oldvsn, S, _Extra) ->
    {ok, S}.
 
%%=====
acceptor(Parent, Lsock, Root) ->
    case gen_tcp:accept(Lsock) of
	{ok, Sock} ->
	    gen_server:cast(Parent, {acceptor, self()}),
	    serverloop(Sock, Root);
	{error, Reason} ->
	    exit(Reason)
    end.

serverloop(Sock, Root) ->
    Req = do_recv(Sock),
    {ok,[Cmd|[Name|[Vers|_]]]} = split(Req,"[ \r\n]"),  
    FileName = Root ++ Name,  
    LogReq = Cmd ++ " " ++ Name ++ " " ++ Vers,  
    Resp = case file:read_file(FileName) of  
	       {ok, Data} ->  
		   io:format("~p ~p ok~n",[LogReq,FileName]),  
		   Data;  
	       {error, Reason} ->  
		   io:format("~p ~p failed ~p~n",[LogReq,FileName,Reason]),  
		   error_response(LogReq,file:format_error(Reason))  
	   end,   
    do_send(Sock,Resp),  
    gen_tcp:close(Sock).

error_response(LogReq,Reason) ->  
    "<html><head><title>Request Failed</title></head><body>\n" ++  
	"<h1>Request Failed</h1>\n" ++ "Your request to " ++ LogReq ++  
	" failed due to: " ++ Reason ++ "\n</body></html>\n".  

do_send(Sock,Msg) ->  
   case gen_tcp:send(Sock, Msg) of  
     ok -> ok;  
       {error, Reason} -> exit(Reason)  
   end.  
   
 %% receive data from the socket  
do_recv(Sock) ->  
   case gen_tcp:recv(Sock, 0) of  
     {ok, Bin} -> binary_to_list(Bin);  
       {error, closed} -> exit(closed);  
      {error, Reason} -> exit(Reason)  
   end.  
